/**
 * 01矩阵，找满足以下模式的最大尺寸
 * 
 * 1001
 * 1010
 * 1100
 * 1111
 * 
 * 对于竖线与横线均可以使用二维前缀和求得，
 * 对角线则不行，因此专门用一个数组Xij记录以ij为起点的反对角线长度
 * Dij记录ij子矩阵的前缀和
 * 
 * 对每一个点ij，首先求出竖线、横线与反对角线的最短长度，记作L
 * 则答案必然在[1, L]之间，注意到答案具有二分性质，因此可以二分
 * 
 * 令d表示子数组的1的数量，则 d == L + L + L - 2 说明该区域满足条件
 * 因此 O(N^2logN) 可以解决。
 * 
 * 竖线与横线不能另开数组，否则会MLE，复用前缀和数组即可
 */
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;

using llt = long long;
using vi = vector<int>;
using vll = vector<llt>;

int N, M;
vector<string> Board;

vector<vi> D;
// vector<vi> Shu;
// vector<vi> Hen;
vector<vi> Xie;

int f(int rmin, int cmin, int rmax, int cmax){
	return D[rmax][cmax] + D[rmin - 1][cmin - 1] - D[rmax][cmin - 1] - D[rmin - 1][cmax];
}

int proc(int r, int c){
    auto check = [&](int mid)->bool{
        int rmax = r;
        int rmin = r - mid + 1;
        int cmin = c;
        int cmax = c + mid - 1;
        if(mid > f(rmin, c, rmax, c)) return false;
		if(mid > f(r, cmin, r, cmax)) return false;
		int tt = D[rmax][cmax] + D[rmin - 1][cmin - 1] - D[rmax][cmin - 1] - D[rmin - 1][cmax];
        return tt == mid + mid + mid - 2;
    };

    int left = 1, right = min(r, M - c + 1), mid;
	right = min(right, Xie[r][c]);
    do{
        mid = (left + right) >> 1;
        if(check(mid)) left = mid + 1;
        else right = mid - 1;
    }while(left <= right);
    return right;
}

int proc(){
    D.assign(N + 2, vi(M + 2, 0));    
    for(int i=1;i<=N;++i)for(int j=1;j<=M;++j){
        auto t = Board[i][j] ^ '0';
        D[i][j] = t + D[i - 1][j] + D[i][j - 1] - D[i - 1][j - 1];
    }

    // Shu.assign(N + 2, vi(M + 2, 0));
    // Hen.assign(N + 2, vi(M + 2, 0));
    // for(int i=N;i>=1;--i)for(int j=M;j>=1;--j){
    //     auto t = Board[i][j] ^ '0';
    //     if(t){            
    //         Hen[i][j] = 1 + Hen[i][j + 1];            
    //     }

    // }

    Xie.assign(N + 2, vi(M + 2, 0));
    for(int i=1;i<=N;++i)for(int j=M;j>=1;--j){
        auto t = Board[i][j] ^ '0';
        if(t){
            Xie[i][j] = 1 + Xie[i - 1][j + 1];
            // Shu[i][j] = 1 + Shu[i - 1][j];
        }
        
    }

#ifndef ONLINE_JUDGE
    // for(int i=1;i<=N;++i)for(int j=1;j<=M;++j){
    //     cout << "(" << i << ", " << j << "):";
    //     cout << D[i][j] << ", " << Shu[i][j] << ", " << Hen[i][j] << ", " << Xie[i][j] << endl;
    // }
#endif

    int ans = 0;
    for(int i=1;i<=N;++i)for(int j=1;j<=M;++j){
        if(Board[i][j] == '0') continue;

        ans = max(ans, proc(i, j));
    }
    return ans;
}

void work(){
    cin >> N >> M;
    Board.assign(N + 1, {});
    for(int i=1;i<=N;++i){
        cin >> Board[i];
        Board[i] = " " + Board[i];
    }
    cout << proc() << endl;
    return;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int nofkase = 1;
    // cin >> nofkase;
    while(nofkase--) work();
    return 0;
}